package gp;

/**
 * This is the base class for all kinds of function nodes (i.e. non-terminals).
 * Each kind of function can have a different number of arguments (i.e.
 * subtrees).
 */
abstract class Function extends Program {

	protected Program[] arg;

	public String toString(int level) {
		// Just to please the eye: If all arguments of the function
		// are terminals, I print a single line instead of spreading the
		// stuff tree-like.
		boolean allArgsAreTerminals = true;

		for (Program p : arg) {
			allArgsAreTerminals = allArgsAreTerminals
					&& (p instanceof Terminal);
		}
		String s = "";
		if (!allArgsAreTerminals) {
			s = indent(level) + getName() + "(\n";
			int i = 0;
			while (i < arg.length - 1) {
				s = (s + arg[i].toString(level + 1) + ",\n");
				i++;
			}
			if (i < arg.length) {
				s = (s + arg[i].toString(level + 1) + "\n");
			}
			s = (s + indent(level) + ")");
		} else {
			s = indent(level) + getName() + "(";
			int i = 0;
			while (i < arg.length - 1) {
				s = (s + arg[i].toString(0) + ",");
				i++;
			}
			if (i < arg.length) {
				s = (s + arg[i].toString(0));
			}
			s = (s + ")");
		}
		return s;
	}

	protected Object clone() {
		Function temp = null;

		try {
			temp = getClass().newInstance();
			for (int i = 0; i < arg.length; i++) {
				temp.arg[i] = (Program) arg[i].clone();
			}
		} catch (Exception e) {
		}
		return temp;
	}

	int countNodes() {
		int count = 1;
		for (Program p : arg) {
			count = (count + p.countNodes());
		}
		return count;
	}

	int countNodes(Condition cond) {
		int count = (cond.test(this) ? 1 : 0);
		for (Program p : arg) {
			count = (count + p.countNodes(cond));
		}
		return count;
	}

}